package test;

import static org.junit.Assert.*;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import dsa.LinkedList;
import dsa.ListIterator;

public class WilliamFoleyTest {

	LinkedList lList;

	/**
	 * Setting up the LinkedList
	 * @throws Exception
	 */
	@Before
	public void setUp() throws Exception {

		lList = new LinkedList();

		lList.addLast("A");
		lList.addLast("B");
		lList.addLast("C");
		lList.addLast("D");
	}
	
	/**
	 * Tearing down the LinkedList
	 * @throws Exception
	 */
	@After
	public void tearDown() throws Exception {
		lList = null;
	}
	/**
	 * Test to confirm the size method works properly and the linked list is properly set up
	 */
	@Test
	public void testSetUp() {

		assertTrue(lList.size()==4);
		assertTrue(lList.get(0).equals("A"));
		assertTrue(lList.get(1).equals("B"));
		assertTrue(lList.get(2).equals("C"));
		assertTrue(lList.get(3).equals("D"));
		//assertNull(lList.get(4));
	}

	/**
	 * Test to confirm remove, removeFirst, and removeLast methods remove specified item and adjusts linked list accordingly
	 * 
	 */
	@Test
	public void testRemove() {

		assertTrue(lList.remove(2).equals("C"));
		assertTrue(lList.size() == 3);
		assertTrue(lList.get(0).equals("A"));
		assertTrue(lList.get(1).equals("B"));
		assertTrue(lList.get(2).equals("D"));
		//assertNull(lList.get(3));
		assertTrue(lList.removeFirst().equals("A"));
		assertTrue(lList.size() == 2);
		assertTrue(lList.get(0).equals("B"));
		assertTrue(lList.get(1).equals("D"));
		//assertNull(lList.get(2));
		//assertNull(lList.get(3));
		assertTrue(lList.removeLast().equals("D"));
		assertTrue(lList.size() == 1);
		assertTrue(lList.get(0).equals("B"));
		//assertNull(lList.get(1));
		//assertNull(lList.get(2));
		//assertNull(lList.get(3));
	}

	/**
	 * Test to confirm the addFirst method properly adds to the beginning of the linked list
	 */
	@Test
	public void testAddFirst() {

		lList.addFirst("Z");
		assertTrue(lList.size() == 5);
		assertTrue(lList.get(0).equals("Z"));
		assertTrue(lList.get(1).equals("A"));
		assertTrue(lList.get(4).equals("D"));
		//assertNull(lList.get(5));
	}

	/**
	 * Test to confirm the addLast method properly adds to the end of the linked list
	 */
	@Test
	public void testAddLast() {

		lList.addLast("Z");
		assertTrue(lList.size() == 5);
		assertTrue(lList.get(0).equals("A"));
		assertTrue(lList.get(4).equals("Z"));
		//assertNull(lList.get(5));
	}

	/**
	 * Test to confirm the get, getFirst, and getLast methods properly return correct values
	 */
	@Test
	public void testGet() {

		assertTrue(lList.getFirst().equals("A"));
		assertTrue(lList.get(0).equals("A"));
		assertTrue(lList.get(1).equals("B"));
		assertTrue(lList.get(2).equals("C"));
		assertTrue(lList.get(3).equals("D"));
		assertTrue(lList.getLast().equals("D"));
		//assertNull(lList.get(10));
		//assertNull(lList.get(-1));
	}

	/**
	 * Test to confirm the indexOf method returns the proper index
	 */
	@Test
	public void testIndexOf() {

		assertTrue(lList.indexOf("A") == 0);
		assertTrue(lList.indexOf("C") == 2);
		assertTrue(lList.indexOf("Z") == -1);
		assertTrue(lList.indexOf(null) == -1);
	}

//	/**
//	 * Test to confirm the lastIndexOf method returns the proper index
//	 */
//	@Test
//	public void testLastIndexOf() {
//		
//		lList.addLast("A");
//		assertTrue(lList.size() == 5);
//		assertTrue(lList.lastIndexOf("A") == 4);
//
//		lList.addLast("B");
//		assertTrue(lList.size() == 6);
//		assertTrue(lList.lastIndexOf("B") == 5);
//	}
//						NOT USED

	/**
	 * Test to confirm the contains method returns the proper boolean response
	 */
	@Test
	public void testContains() {

		assertTrue(lList.contains("A"));
		assertFalse(lList.contains(null));
		assertFalse(lList.contains("Z")); 
	}

	/**
	 * Test to confirm the set method properly sets objects in correct index, and returns old value
	 */
	@Test
	public void testSet() {

		//assertNull(lList.set(-1, "Z")); //returns null when index < 0
		//assertNull(lList.set(10, "Z")); //returns null when index > size
		//assertNull(lList.set(1, null)); //returns null when object is null
		assertTrue(lList.set(0, "Z").equals("A"));
		assertTrue(lList.get(0).equals("Z"));
		assertTrue(lList.set(3, "Z").equals("D"));
		assertTrue(lList.get(3).equals("Z"));
	}

	/**
	 * Test to confirm the toArray method properly creates an array from the provided linked list
	 */
	@Test
	public void testToArray() {

		Object[] array2 = new Object[lList.size()];
		array2[0] = "A";
		array2[1] = "B";
		array2[2] = "C";
		array2[3] = "D";
		assertArrayEquals(array2, lList.toArray()); //two arrays have same elements
	}

	/**
	 * Test to confirm the clone method creates a shallow copy of the linked list
	 */
	@Test
	public void testClone() {

		LinkedList clone = (LinkedList) lList.clone();
		for(int i = 0; i < lList.size(); i++){
			assertTrue(clone.get(i).equals(lList.get(i)));
		}
	}
	
	/**
	 * Test to confirm the list clears completely then is repopulated correctly
	 */
	@Test
	public void testClear() {
		assertTrue(lList.size() == 4);
		int num = lList.size();
		for(int i = 0; i < num; i++){
			lList.remove(0);
		}
		assertTrue(lList.size() == 0);
		//List is completely cleared from above loop
		lList.addFirst("d");
		lList.addFirst("c");
		lList.addFirst("b");
		lList.addFirst("a");
		assertTrue(lList.getFirst().equals("a"));
		assertTrue(lList.getLast().equals("d"));
		assertTrue(lList.get(1).equals("b"));
		assertTrue(lList.get(2).equals("c"));
		//assertNull(lList.get(4));
		//assertNull(lList.get(-1));
		assertTrue(lList.size() == 4);
		//List repopulated using the addFirst method with lowercase letters
	}
	
	/**
	 * ListIterator
	 */
	@Test
	public void testListIterator(){
		ListIterator lI = lList.listIterator(0);
		assertTrue(lI.nextIndex() == 1);
		assertTrue(lI.next().equals("A"));
		assertTrue(lI.previousIndex() == 0);
		assertTrue(lI.nextIndex() == 2);
		assertTrue(lI.next().equals("B"));
		assertTrue(lI.previousIndex() == 1);
		assertTrue(lI.nextIndex() == 3);
		assertTrue(lI.next().equals("C"));
		assertTrue(lI.previousIndex() == 2);
		assertTrue(lI.nextIndex() == 4);
		assertTrue(lI.next().equals("D"));
		
		assertFalse(lI.hasNext());
		assertTrue(lI.hasPrevious());
		
		assertTrue(lI.previous().equals("D"));
		assertTrue(lI.previous().equals("C"));
		assertTrue(lI.previous().equals("B"));
		assertTrue(lI.previous().equals("A"));
		
		lI.remove();
		assertFalse(lI.hasPrevious());
		assertTrue(lI.next().equals("B"));
		
		lI.set("b");
		assertTrue(lI.previous().equals("b"));
		
		lI.add("a");
		assertTrue(lI.previous().equals("a"));
		
	}
}
